package com.cneport.das.common.security.pub;


import javax.crypto.Cipher;
import java.security.Key;

/**
 * RSA + AES 混合加密工具类
 */
public class SymmetricWithRSAValueEncoder implements java.io.Serializable
{
	final static int MAGIC = ('S'<<24) |('N'<<16) | ('S'<<8) | 'R'; 
	private static final long serialVersionUID = -3300551395336830739L;
	Key key;
	java.security.Key					symmetricEncodeKey;
	public SymmetricWithRSAValueEncoder(Key key)
	{
		this.key = key;
		this.symmetricEncodeKey = AESValueEncoder.newKey();
	}

	public byte[] encode(byte[] value)
	{
		try {
			AESValueEncoder encoder = new AESValueEncoder(symmetricEncodeKey);
			Cipher cp = Cipher.getInstance("RSA");
			cp.init(Cipher.ENCRYPT_MODE, this.key);
			byte encodedKey[] = cp.doFinal( encoder.getEncodedKey());
			if( encodedKey.length>0xffff )
				throw new AssertionError();
			final java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
			final java.io.DataOutputStream os = new java.io.DataOutputStream(out);
			os.writeInt(MAGIC);
			os.write(0); // version
			os.write(0); // options
			os.writeShort(encodedKey.length);
			os.write(encodedKey);
			final byte encodeData[] = encoder.encode(value);
			os.writeInt(encodeData.length);
			out.write(encodeData);
			return out.toByteArray();
		} catch( Throwable ex)
		{
			throw new RuntimeException(ex);
		}
	}

	public byte[] decode(byte[] value)
	{
		try {
			final java.io.DataInputStream is = new java.io.DataInputStream(new java.io.ByteArrayInputStream(value));
			if( is.readInt()!=MAGIC )
				throw new IllegalArgumentException("数据格式错误");
			is.readByte();  // versio
			is.readByte();  // options
			final byte encodedKey[] = new byte[is.readShort()];
			is.readFully(encodedKey);
			Cipher cp = Cipher.getInstance("RSA");
			cp.init(Cipher.DECRYPT_MODE,this.key);
			final byte[] key = cp.doFinal(encodedKey);
			AESValueEncoder encoder = new AESValueEncoder(key);;
			final byte encodedData[] = new byte[is.readInt()];
			is.readFully(encodedData);
			return encoder.decode(encodedData);
		} catch( Throwable ex)
		{
			throw new RuntimeException(ex);
		}
	}

}
